# SPDX-License-Identifier: GPL-2.0-or-later

import bpy

from ...base_rig import BaseRig

from ...utils.naming import strip_org, make_deformer_name
from ...utils.widgets import layout_widget_dropdown, create_registered_widget
from ...utils.widgets_basic import create_bone_widget

from .raw_copy import RelinkConstraintsMixin


class Rig(BaseRig, RelinkConstraintsMixin):
    """ A "copy" rig.  All it does is duplicate the original bone and
        constrain it.
        This is a control and deformation rig.
    """

    bones: BaseRig.ToplevelBones[str, str, str, str]

    org_name: str

    make_control: bool
    make_widget: bool
    make_deform: bool

    def find_org_bones(self, pose_bone) -> str:
        return pose_bone.name

    def initialize(self):
        """ Gather and validate data about the rig.
        """
        self.org_name = strip_org(self.bones.org)

        self.make_control = self.params.make_control
        self.make_widget = self.params.make_widget
        self.make_deform = self.params.make_deform

    def generate_bones(self):
        bones = self.bones

        # Make a control bone (copy of original).
        if self.make_control:
            bones.ctrl = self.copy_bone(bones.org, self.org_name, parent=True)

        # Make a deformation bone (copy of original, child of original).
        if self.make_deform:
            bones.deform = self.copy_bone(bones.org, make_deformer_name(self.org_name), bbone=True)

    def parent_bones(self):
        bones = self.bones

        if self.make_deform:
            self.set_bone_parent(bones.deform, bones.org, use_connect=False)

        new_parent = self.relink_bone_parent(bones.org)

        if self.make_control and new_parent:
            self.set_bone_parent(bones.ctrl, new_parent)

    def configure_bones(self):
        bones = self.bones

        if self.make_control:
            self.copy_bone_properties(bones.org, bones.ctrl)

    def rig_bones(self):
        bones = self.bones

        self.relink_bone_constraints(bones.org)

        if self.make_control:
            self.relink_move_constraints(bones.org, bones.ctrl, prefix='CTRL:')

            # Constrain the original bone.
            self.make_constraint(bones.org, 'COPY_TRANSFORMS', bones.ctrl, insert_index=0)

        if self.make_deform:
            self.relink_move_constraints(bones.org, bones.deform, prefix='DEF:')

    def generate_widgets(self):
        bones = self.bones

        if self.make_control:
            # Create control widget
            if self.make_widget:
                create_registered_widget(self.obj, bones.ctrl,
                                         self.params.super_copy_widget_type or 'circle')
            else:
                create_bone_widget(self.obj, bones.ctrl)

    @classmethod
    def add_parameters(cls, params):
        """ Add the parameters of this rig type to the
            RigifyParameters PropertyGroup
        """
        params.make_control = bpy.props.BoolProperty(
            name="Control",
            default=True,
            description="Create a control bone for the copy"
        )

        params.make_widget = bpy.props.BoolProperty(
            name="Widget",
            default=True,
            description="Choose a widget for the bone control"
        )

        params.super_copy_widget_type = bpy.props.StringProperty(
            name="Widget Type",
            default='circle',
            description="Choose the type of the widget to create"
        )

        params.make_deform = bpy.props.BoolProperty(
            name="Deform",
            default=True,
            description="Create a deform bone for the copy"
        )

        cls.add_relink_constraints_params(params)

    @classmethod
    def parameters_ui(cls, layout, params):
        """ Create the ui for the rig parameters.
        """
        layout.prop(params, "make_control")

        row = layout.split(factor=0.3)
        row.prop(params, "make_widget")
        row.enabled = params.make_control

        row2 = row.row(align=True)
        row2.enabled = params.make_widget
        layout_widget_dropdown(row2, params, "super_copy_widget_type", text="")

        layout.prop(params, "make_deform")

        cls.add_relink_constraints_ui(layout, params)

        if params.relink_constraints and (params.make_control or params.make_deform):
            col = layout.column()
            if params.make_control:
                col.label(text="'CTRL:...' constraints are moved to the control bone.", icon='INFO')
            if params.make_deform:
                col.label(text="'DEF:...' constraints are moved to the deform bone.", icon='INFO')


def create_sample(obj):
    """ Create a sample metarig for this rig type.
    """
    # generated by rigify.utils.write_metarig
    bpy.ops.object.mode_set(mode='EDIT')
    arm = obj.data

    bones = {}

    bone = arm.edit_bones.new('Bone')
    bone.head[:] = 0.0000, 0.0000, 0.0000
    bone.tail[:] = 0.0000, 0.0000, 0.2000
    bone.roll = 0.0000
    bone.use_connect = False
    bones['Bone'] = bone.name

    bpy.ops.object.mode_set(mode='OBJECT')
    pbone = obj.pose.bones[bones['Bone']]
    pbone.rigify_type = 'basic.super_copy'
    pbone.lock_location = (False, False, False)
    pbone.lock_rotation = (False, False, False)
    pbone.lock_rotation_w = False
    pbone.lock_scale = (False, False, False)
    pbone.rotation_mode = 'QUATERNION'

    bpy.ops.object.mode_set(mode='EDIT')
    for bone in arm.edit_bones:
        bone.select = False
        bone.select_head = False
        bone.select_tail = False
    for b in bones:
        bone = arm.edit_bones[bones[b]]
        bone.select = True
        bone.select_head = True
        bone.select_tail = True
        arm.edit_bones.active = bone

    return bones
